package com.black.cat.jvm;

import com.black.cat.jvm.classfile.ClassFile;
import com.black.cat.jvm.classfile.MemberInfo;
import com.black.cat.jvm.classfile.attribute.AttributeInfo;
import com.black.cat.jvm.classpath.Classpath;


/**
 * @Author blackcat
 * @create 2021/8/11 13:43
 * @version: 1.0
 * @description:命令行工具
 */
public class Main {

    public static void main(String[] args) {
        String[] argv = {"-classpath", "D:\\develop\\code\\jjvm\\jvm-03\\target\\classes", "com.black.cat.jvm.MainTest"};
        Cmd cmd = Cmd.parse(argv);
        if (!cmd.ok || cmd.helpFlag) {
            System.out.println("Usage: <main class> [-options] class [args...]");
            return;
        }
        if (cmd.versionFlag) {
            System.out.println("java version \"1.8.0\"");
            return;
        }
        startJVM(cmd);
    }

    private static void startJVM(Cmd cmd) {
        System.out.printf("classpath:%s class:%s args:%s\n", cmd.classpath, cmd.getMainClass(), cmd.getAppArgs());

        Classpath classpath = new Classpath(null, cmd.classpath);

        String className = cmd.getMainClass().replace(".", "/");

        ClassFile classFile = loadClass(className, classpath);
        assert classFile != null;
        printClassInfo(classFile);
    }

    private static ClassFile loadClass(String className, Classpath classpath) {
        try {
            byte[] classData = classpath.readClass(className);
            return new ClassFile(classData);
        } catch (Exception e) {
            System.out.println("Could not find or load main class " + className);
            return null;
        }
    }

    //使用 javap -verbose  MainTest查看所有常量池进行比对
    private static void printClassInfo(ClassFile cf) {
        System.out.println("version: " + cf.getMajorVersion() + "." + cf.getMinorVersion());
        System.out.println("constants count：" + cf.getConstantPool().getSize());
        for (int i = 1; i < cf.getConstantPool().getSize(); i++) {
            System.out.println("constants" + i + "：" + cf.getConstantPool().getConstantInfos()[i]);
        }

        System.out.format("access flags：0x%x\n", cf.getAccessFlag());
        System.out.println("this classindex：" + cf.getClassNameIndex());
        System.out.println("this class：" + cf.getConstantPool().getUtfStringByIndex(cf.getClassNameIndex()));
        System.out.println("super classindex：" + cf.getSuperClassNameIndex());
        System.out.println("super class：" + cf.getConstantPool().getUtfStringByIndex(cf.getSuperClassNameIndex()));
        System.out.println("interfaceCount：" + cf.getInterfaceIndexes().length);

        for (int interfaceIndex : cf.getInterfaceIndexes()) {
            System.out.println("interfaces：" + cf.getConstantPool().getUtfStringByIndex(interfaceIndex));
        }

        System.out.println("fields count：" + cf.getFieldInfos().length);
        for (MemberInfo memberInfo : cf.getFieldInfos()) {
            System.out.format("  %s\n", memberInfo.toString());
        }
        System.out.println("methods count: " + cf.getMethodInfos().length);
        for (MemberInfo memberInfo : cf.getMethodInfos()) {
            System.out.format("  %s\n", memberInfo.toString());
        }

        System.out.println("attribute count: " + cf.getAttributeInfos().length);
        for (AttributeInfo attributeInfo : cf.getAttributeInfos()) {
            System.out.format("  %s\n", attributeInfo.toString());
        }
    }
}
